In [1]:
import os
import math
import numpy as np
import pandas as pd
import dill as pickle
import plotly
import plotly.graph_objects as go
import plotly.express as px

import matplotlib.pyplot as plt
from matplotlib import image
import openpyxl
import torch
import imageio

Data: https://disk.yandex.ru/d/TTMAnvbg5KlBGQ/Circuar_Robots_Experiments

Each .pickle file corresponds to one video and contains a list of lists with the results of frame-by-frame recognition in the following format: [robot_id (int), orientation_degree (float), position (tuple)]

Video of selected experiment: https://disk.yandex.ru/d/TTMAnvbg5KlBGQ/Circuar_Robots_Experiments/120_450_%5B40_bots_D_41_cm%5D.mp4

In [2]:
with open(f'experiment_data/120_450_[40_bots_D_41_cm].pickle', 'rb') as file:
    data = pickle.load(file)
In [3]:
keys_list = [inner_list[0] for inner_list in data[0]]
In [4]:
dict_variable = {i:[] for i in keys_list} # {1: [], 2: [], ...}
In [5]:
for inner_list in data[:]:
    for item in inner_list:
        key = item[0]
        value = item[1]
        if key in dict_variable:
            dict_variable[key].append(value)
        else:
            dict_variable[key] = [value]
In [6]:
coord_data = {}

for inner_list in data:
    for item in inner_list:
        key = item[0]
        coordinates = item[2]
        if key in coord_data:
            coord_data[key].append(coordinates)
        else:
            coord_data[key] = [coordinates]

Dynamics of a single robot without external influence (/experiment_1)¶

In [7]:
frequency = 1
object_key = 39
x_object_key_39 = [coord[0] for coord in coord_data[39]][:2750:frequency]
y_object_key_39 = [coord[1] for coord in coord_data[39]][:2750:frequency]
t_object_key_39 = list(range(0, len(coord_data[39])))[:2750:frequency]

Models:

$\begin{equation} \left\{\begin{array}{@{}l@{}} \frac{\partial^2 x}{\partial t^2} = F_1(t, x, y | \dot{x}, \dot{y}),\\ \frac{\partial^2 y}{\partial t^2} = F_2(t, x, y | \dot{x}, \dot{y}), \end{array}\right. \end{equation}$

Equations:

$t \in [0, 500)$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial^2 x}{\partial t^2} = C_1 \cdot y + C_2 \cdot x + C_x ,\\ \frac{\partial^2 y}{\partial t^2} = C_3 \cdot x + C_4 \cdot y + C_y, \end{array} \right.$

C1, C2, C_x = [0.005009749664145631, 0.003853403655544636, -5.949294944691131]
C3, C4, C_y = [-0.000275798490503857, -0.0002370639399209363, 0.34497930475479666]

$t \in [500, 1300)$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial^2 x}{\partial t^2} = C_1 \cdot \dot{y} + C_x ,\\ \frac{\partial^2 y}{\partial t^2} = C_2 \cdot \dot{y} + C_3 \cdot \dot{x} + C_y, \end{array} \right.$

 C1, C2, C_x = [0.022103208593336574, 0, -0.0006651888415115347]
 C3, C4, C_y = [0.005066679345402518, -0.010193737624644827, 0.0012643635643993347]

$t \in [1300, 2300)$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial^2 x}{\partial t^2} = C_1 \cdot \dot{y} + C_x ,\\ \frac{\partial^2 y}{\partial t^2} = C_2 \cdot \dot{x} + C_3 \cdot y + C_y, \end{array} \right.$

C1, C2, C_x = [0.007985714155100692, 0, -0.0017552519711892523]
C3, C4, C_y = [-0.012111875017715061, -0.00013275431568060997, 0.0823294578859809]

$t \in [2300, 2750]$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial^2 x}{\partial t^2} = C_1 \cdot y + C_2 \cdot x + C_x ,\\ \frac{\partial^2 y}{\partial t^2} = C_3 \cdot x + C_4 \cdot y + C_y, \end{array} \right.$

C1, C2, C_x = [-0.00016436314975088633, -0.00021888086551946753, 0.35508484551095787]
C3, C4, C_y = [-0.00011488879169921345, -0.0004462139777650353, 0.3760244175016091]
In [8]:
with open(f'experiment_1/solution_1_object_39_eq3_0_500.npy', 'rb') as f:
    x_sol, y_sol, t_sol = np.load(f)

with open(f'experiment_1/solution_1_object_39_eq7_500_1300.npy', 'rb') as f:
    x_sol2, y_sol2, t_sol2 = np.load(f)

with open(f'experiment_1/solution_1_object_39_eq9_1300_2300.npy', 'rb') as f:
    x_sol3, y_sol3, t_sol3 = np.load(f)    

with open(f'experiment_1/solution_1_object_39_eq10_2300_2750.npy', 'rb') as f:
    x_sol4, y_sol4, t_sol4 = np.load(f) 
In [9]:
fig = go.Figure()

fig.add_trace(go.Scatter(x=t_object_key_39, y=x_object_key_39[:2750], legendgroup='1', line=dict(color='LightSalmon', width=1), mode='lines', name=f'X Coordinate, object - {object_key}'))
fig.add_trace(go.Scatter(x=t_object_key_39, y=y_object_key_39[:2750], legendgroup='1', line=dict(color='CornflowerBlue', width=1), mode='lines', name=f'Y Coordinate, object - {object_key}'))

fig.add_trace(go.Scatter(x=t_sol, y=x_sol, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', name=f'X Coordinate (solution), object - {object_key}'))
fig.add_trace(go.Scatter(x=t_sol, y=y_sol, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', name=f'Y Coordinate (solution), object - {object_key}'))

fig.add_trace(go.Scatter(x=t_sol2, y=x_sol2, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))
fig.add_trace(go.Scatter(x=t_sol2, y=y_sol2, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))

fig.add_trace(go.Scatter(x=t_sol3, y=x_sol3, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))
fig.add_trace(go.Scatter(x=t_sol3, y=y_sol3, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))

fig.add_trace(go.Scatter(x=t_sol4, y=x_sol4, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))
fig.add_trace(go.Scatter(x=t_sol4, y=y_sol4, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))



fig.add_trace(go.Scatter(x=[2300, 2300], y=[300, 1300],
                         mode='lines', line=dict(color='black', width=2), legendgroup='boundary', showlegend=False))
fig.add_trace(go.Scatter(x=[1300, 1300], y=[300, 1300],
                         mode='lines', line=dict(color='black', width=2), legendgroup='boundary', showlegend=False))
fig.add_trace(go.Scatter(x=[500, 500], y=[300, 1000],
                         mode='lines', line=dict(color='black', width=2), legendgroup='boundary', showlegend=False))

fig.update_xaxes(title="Time")
fig.update_yaxes(title="Coordinates")

fig.update_layout(
    legend=dict(
        x=0.02,
        y=0.98,
        xanchor='left',
        yanchor='top',
        bgcolor='rgba(255, 255, 255, 0.5)',
        bordercolor='Black',
        borderwidth=1,
        
    )
)

fig.update_layout(
    font_family="Inter Medium",
    plot_bgcolor='white',
    showlegend=True,
    margin=dict(l=0, r=0, t=0, b=0),
    height=400, width=900
)

fig.update_xaxes(
    showgrid=False,
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey',
    dtick=250,
)
fig.update_yaxes(
    showgrid=False,
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey',
    dtick=200,
)

fig.show()

Dynamics of a single robot with external influence (/experiment_2)¶

In [10]:
data39_smooth = pd.read_excel(f'experiment_data/data_1_object_39_smooth.xlsx')
data40_smooth = pd.read_excel(f'experiment_data/data_1_object_40_smooth.xlsx')
data68_smooth = pd.read_excel(f'experiment_data/data_1_object_68_smooth.xlsx')

x39_smooth = np.array(data39_smooth['x'])[::frequency]
y39_smooth = np.array(data39_smooth['y'])[::frequency]

x40_smooth = np.array(data40_smooth['x'])[::frequency]
y40_smooth = np.array(data40_smooth['y'])[::frequency]

x68_smooth = np.array(data68_smooth['x'])[::frequency]
y68_smooth = np.array(data68_smooth['y'])[::frequency]

t_smooth = np.array(data39_smooth['t'])[::frequency]
In [11]:
x_object_key_40 = [coord[0] for coord in coord_data[40]][:2750:frequency]
y_object_key_40 = [coord[1] for coord in coord_data[40]][:2750:frequency]

x_object_key_68 = [coord[0] for coord in coord_data[68]][:2750:frequency]
y_object_key_68 = [coord[1] for coord in coord_data[68]][:2750:frequency]
In [12]:
from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(rows=2, cols=1,
                    shared_xaxes=True,
                    vertical_spacing=0.02)


fig.add_trace(go.Scatter(x=t_object_key_39, y=x_object_key_39, legendgroup='39', mode='lines', line=dict(color='DarkOrange', width=1), name=f'X, Y Coordinates, object - {object_key}'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=t_object_key_39, y=x_object_key_40, legendgroup='40', mode='lines', line=dict(color='Plum', width=1), name=f'X, Y Coordinates, object - {40}'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=t_object_key_39, y=x_object_key_68, legendgroup='68', mode='lines', line=dict(color='YellowGreen', width=1), name=f'X, Y Coordinates, object - {68}'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=t_smooth, y=x39_smooth, legendgroup='2', mode='lines', line=dict(color='OrangeRed', width=2), name=f'X, Y Coordinates (smooth), object  - 39'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=t_smooth, y=x40_smooth, legendgroup='4', mode='lines', line=dict(color='Magenta', width=2), name=f'X, Y Coordinates (smooth), object - 40'),
              row=1, col=1)

fig.add_trace(go.Scatter(x=t_smooth, y=x68_smooth, legendgroup='5', mode='lines', line=dict(color='DarkGreen', width=2), name=f'X, Y Coordinates (smooth), object - 68'),
              row=1, col=1)


fig.add_trace(go.Scatter(x=t_object_key_39, y=y_object_key_39, legendgroup='39', mode='lines', line=dict(color='DarkOrange', width=1), showlegend=False, name=f'Координата Y, объект - {object_key}'),
              row=2, col=1)

fig.add_trace(go.Scatter(x=t_object_key_39, y=y_object_key_40, legendgroup='40', mode='lines', line=dict(color='Plum', width=1), showlegend=False,  name=f'Координата Y, объект - {40}'),
              row=2, col=1)

fig.add_trace(go.Scatter(x=t_object_key_39, y=y_object_key_68, legendgroup='68', mode='lines', line=dict(color='YellowGreen', width=1), showlegend=False,  name=f'Координата Y, объект - {68}'),
              row=2, col=1)

fig.add_trace(go.Scatter(x=t_smooth, y=y39_smooth, legendgroup='2', mode='lines', line=dict(color='OrangeRed', width=2), showlegend=False, name=f'Координата Y (smooth), объект - 39'),
              row=2, col=1)

fig.add_trace(go.Scatter(x=t_smooth, y=y40_smooth, legendgroup='4', mode='lines', line=dict(color='Magenta', width=2), showlegend=False, name=f'Координата Y (smooth), объект - 40'),
              row=2, col=1)

fig.add_trace(go.Scatter(x=t_smooth, y=y68_smooth, legendgroup='5', mode='lines', line=dict(color='DarkGreen', width=2), showlegend=False, name=f'Координата Y (smooth), объект - 68'),
              row=2, col=1)

fig.update_layout(
    legend=dict(
        x=0.02,
        y=0.98,
        xanchor='left',
        yanchor='top',
        bgcolor='rgba(255, 255, 255, 0.5)',
        bordercolor='Black',
        borderwidth=1
    )
)

fig.update_layout(
    font_family="Inter Medium",
    plot_bgcolor='white',
    showlegend=True,
    margin=dict(l=0, r=0, t=0, b=0),
    height=600, width=1000
)

fig.update_xaxes(
    showgrid=False,
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey',
    dtick=250,
)
fig.update_yaxes(
    showgrid=False,
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey'
)

fig.layout.legend.tracegroupgap = 1
fig.update_yaxes(title_text="X Coordinate", dtick=100, row=1, col=1)
fig.update_yaxes(title_text="Y Coordinate", dtick=100, row=2, col=1)
fig.update_xaxes(title_text="Time", row=2, col=1)

fig.show()

Models:

$\begin{equation} \left\{\begin{array}{@{}l@{}} \frac{\partial x_1}{\partial t} = F_1(x_1, y_1, t; x_2, y_2, x_3, y_3| \dot{x}_2, \dot{y}_2, \dot{x}_3, \dot{y}_3)=F_1(x_1, y_1, t) + \widetilde{F}_1(t),\\ \frac{\partial y_1}{\partial t} = F_2(x_1, y_1, t; x_2, y_2, x_3, y_3| \dot{x}_2, \dot{y}_2, \dot{x}_3, \dot{y}_3)=F_2(x_1, y_1, t) + \widetilde{F}_2(t), \end{array}\right. \end{equation}$

Equations:

$t \in [0, 500)$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial x_1}{\partial t} = C_1 \cdot y_1 + C_2 \cdot y_2 + C_3 \cdot \frac{\partial y_3}{\partial t} + C_{x_1},\\ \frac{\partial y_1}{\partial t} = C_4 \cdot y_1 + C_5 \cdot y_3 + C_6 \cdot \frac{\partial x_2}{\partial t} + C_{y_1}, \end{array} \right.$

C1, C2, C3, C_x = [0.006352005103549863, -0.7281677803285325, -0.011677970753211198, 8.228837839125529]
C4, C5, C6, C_y = [-0.005376865966488675, 0.4136473459579364, -0.5371054901006438, 2.5407965716671868]

$t \in [500, 1300)$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial x_1}{\partial t} = C_1 \cdot y_1 + C_2 \cdot y_2 + C_3 \cdot \frac{\partial y_3}{\partial t} + C_{x_1},\\ \frac{\partial y_1}{\partial t} = C_4 \cdot y_1 + C_5 \cdot y_3 + C_6 \cdot \frac{\partial x_2}{\partial t} + C_{y_1}, \end{array} \right.$

C1, C2, C3, C_x = [0.021627554302474473, 0.004150957847691688, -0.3644713326024231, -12.751306899814368]
C4, C5, C6, C_y = [-0.01158767087391813, 0.03028635437329039, -5.122064464383909, -6.886560887379993]

$t \in [1300, 2300)$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial x_1}{\partial t} = C_1 \cdot y_1 + C_2 \cdot x_3 + C_3 \cdot \frac{\partial y_3}{\partial t} + C_{x_1} ,\\ \frac{\partial y_1}{\partial t} = C_4 \cdot x_1 + C_5 \cdot \frac{\partial y_2}{\partial t} + C_6 \cdot \frac{\partial x_2}{\partial t} + C_{y_1}, \end{array} \right.$

C1, C2, C3, C_x = [0.009847870663837842, -0.005478351862268577, -0.3573265456599717, 0.4067302350762966]
C4, C5, C6, C_y = [-0.005679856162450192, -0.8873367954290172, -1.191960638689152, 6.4798872952100215]

$t \in [2300, 2750]$ - $\left\{ \begin{array}{@{}l@{}} \frac{\partial x_1}{\partial t} = C_1 \cdot x_1 + C_2 \cdot \frac{\partial y_3}{\partial t} + C_{x_1},\\ \frac{\partial y_1}{\partial t} = C_3 \cdot y_1 + C_4 \cdot \frac{\partial y_3}{\partial t} + C_{y_1}, \end{array} \right.$

C1, C2, C_x = [0.0035941037082182076, -2.0170858029831833, -4.504109328568838]
C3, C4, C_y = [-0.004990811364273184, 0.9698762695386662, 2.6457950824093137]
In [13]:
with open(f'experiment_2/solution_1_object_39_eq_n4_0_500_mat_with_robot_[68, 40].npy', 'rb') as f:
    x_sol, y_sol, t_sol = np.load(f)
    
with open(f'experiment_2/solution_1_object_39_eq_n7_500_1300_mat_with_robot_[68, 40].npy', 'rb') as f:
    x_sol2, y_sol2, t_sol2 = np.load(f)

with open(f'experiment_2/solution_1_object_39_eq_n8_1300_2300_mat_with_robot_[68, 40].npy', 'rb') as f:
    x_sol3, y_sol3, t_sol3 = np.load(f)    

with open(f'experiment_2/solution_1_object_39_eq_n9_2300_2750_mat_with_robot_[68, 40].npy', 'rb') as f:
    x_sol4, y_sol4, t_sol4 = np.load(f)
In [14]:
import plotly.graph_objects as go
fig = go.Figure()

fig.add_trace(go.Scatter(x=t_object_key_39, y=x_object_key_39[:2750], legendgroup='1', line=dict(color='LightSalmon', width=1), mode='lines', name=f'X Coordinate, object - {object_key}'))
fig.add_trace(go.Scatter(x=t_object_key_39, y=y_object_key_39[:2750], legendgroup='1', line=dict(color='CornflowerBlue', width=1), mode='lines', name=f'Y Coordinate, object - {object_key}'))

fig.add_trace(go.Scatter(x=t_sol, y=x_sol, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', name=f'X Coordinate (solution), object - {object_key}'))
fig.add_trace(go.Scatter(x=t_sol, y=y_sol, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', name=f'Y Coordinate (solution), object - {object_key}'))

fig.add_trace(go.Scatter(x=t_sol2, y=x_sol2, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))
fig.add_trace(go.Scatter(x=t_sol2, y=y_sol2, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))

fig.add_trace(go.Scatter(x=t_sol3, y=x_sol3, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))
fig.add_trace(go.Scatter(x=t_sol3, y=y_sol3, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))

fig.add_trace(go.Scatter(x=t_sol4, y=x_sol4, line=dict(color='firebrick', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))
fig.add_trace(go.Scatter(x=t_sol4, y=y_sol4, line=dict(color='Blue', dash='dash', width=2), legendgroup='2', mode='lines', showlegend=False))


fig.add_trace(go.Scatter(x=[2300, 2300], y=[300, 1300],
                         mode='lines', line=dict(color='black', width=2), legendgroup='boundary', showlegend=False))
fig.add_trace(go.Scatter(x=[1300, 1300], y=[300, 1300],
                         mode='lines', line=dict(color='black', width=2), legendgroup='boundary', showlegend=False))
fig.add_trace(go.Scatter(x=[500, 500], y=[300, 1000],
                         mode='lines', line=dict(color='black', width=2), legendgroup='boundary', showlegend=False))

fig.update_xaxes(title="Time")
fig.update_yaxes(title="Coordinates")

fig.update_layout(
    legend=dict(
        x=0.02,
        y=0.98,
        xanchor='left',
        yanchor='top',
        bgcolor='rgba(255, 255, 255, 0.5)',
        bordercolor='Black',
        borderwidth=1,
    )
)

fig.update_layout(
    font_family="Inter Medium",
    plot_bgcolor='white',
    showlegend=True,
    margin=dict(l=0, r=0, t=0, b=0),
    height=400, width=900
)

fig.update_xaxes(
    showgrid=False,
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey',
    dtick=250,
)
fig.update_yaxes(
    showgrid=False,
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey',
    dtick=200,
)

fig.show()

General robots dynamics (/experiment_3)¶

Data preprocessing¶

In [15]:
df_smooth = pd.read_excel(f'experiment_3/coordinates_smooth.xlsx')
In [16]:
coord_data_smooth = {}
for col in df_smooth.columns:
    if col.startswith("x_"):
        id_ = int(col.split("_")[1])
        x_values = df_smooth[col].tolist()
        y_values = df_smooth[f"y_{id_}"].tolist()
        coord_data_smooth[id_] = list(zip(x_values, y_values))
        
frequency = 30
end = len(coord_data_smooth)
In [17]:
import plotly.graph_objects as go

fig = go.Figure()
x_min, x_max, y_min, y_max = float('inf'), float('-inf'), float('inf'), float('-inf')

for key, coordinates in coord_data_smooth.items():
    x_coordinates = [coord[0] for coord in coordinates][:2750:frequency]
    y_coordinates = [coord[1] for coord in coordinates][:2750:frequency]
    
    x_min = min(x_min, min(x_coordinates))
    x_max = max(x_max, max(x_coordinates))
    y_min = min(y_min, min(y_coordinates))
    y_max = max(y_max, max(y_coordinates))
    
    fig.add_trace(go.Scatter(
        x=x_coordinates[:int(len(x_coordinates))],
        y=y_coordinates[:int(len(x_coordinates))],
        mode='lines+markers',
        name=f'Object {key}',
        marker=dict(size=8)
    ))


fig.update_layout(
    font_family="Inter Medium",
    xaxis=dict(title='X Coordinate'),
    yaxis=dict(title='Y Coordinate'),
    showlegend=True
)
fig.update_layout(
    plot_bgcolor='white'
)
fig.update_xaxes(
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey'
)
fig.update_yaxes(
    mirror=True,
    ticks='outside',
    showline=True,
    linecolor='black',
    gridcolor='lightgrey'
)

fig.show()
In [18]:
import plotly.graph_objects as go
fig = go.Figure()

for key, coordinates in coord_data_smooth.items():
    x_plot = [coord[0] for coord in coordinates][:2750:frequency]
    y_plot = [coord[1] for coord in coordinates][:2750:frequency]
    t_plot = list(range(0, len(coordinates)))[:2750:frequency]

    fig.add_trace(go.Scatter3d(x=t_plot, y=x_plot, z=y_plot,
                                    marker=dict(
                                        size=4,
                                        color=y_plot,
                                        colorscale='Viridis'),
                                    line=dict(color='darkblue', width=2),
                                    mode='lines+markers',
                                    name=f'Object {key}'
                                   ))

fig.update_layout(
width=1000,
height=800,
autosize=False,
scene=dict(
    aspectratio = dict(x=1.5, y=0.5, z=0.5),
    aspectmode = 'manual',
    xaxis_title="Time, t",
    yaxis_title="Coordinate, X",
    zaxis_title="Coordinate, Y")
)
    
fig.update_layout(
    font_family="Inter Medium",
    showlegend=False,
)


fig.show()
In [19]:
max_element_x, max_element_y = 0, 0
min_element_x, min_element_y = coord_data_smooth[1][0]

for key, coordinates in coord_data_smooth.items():
    max_x = max([coord[0] for coord in coordinates])
    min_x = min([coord[0] for coord in coordinates])
    max_y = max([coord[1] for coord in coordinates])
    min_y = min(([coord[1] for coord in coordinates]))
    
    if max_element_x < max_x:
        max_element_x = max_x
    if max_element_y < max_y:
        max_element_y = max_y
    if min_element_x > min_x:
        min_element_x = min_x
    if min_element_y > min_y:
        min_element_y = min_y
In [20]:
print(f'min_x = {min_element_x}, max_x = {max_element_x}, difference = {max_element_x - min_element_x}')
print(f'min_y = {min_element_y}, max_y = {max_element_y}, difference = {max_element_y - min_element_y}')

radius = (max_element_x - min_element_x)/2
x_0, y_0 = min_element_x + radius, min_element_y + radius
print(f'Сenter: x = {x_0}, y = {y_0}')
min_x = 793.3675321208935, max_x = 1301.974886256334, difference = 508.60735413544046
min_y = 299.2575797064787, max_y = 819.945985542358, difference = 520.6884058358794
Сenter: x = 1047.6712091886138, y = 553.5612567741989

We've chosen a range $t \in [80, 700]$ for the example.

In [21]:
frequency = 1
end = 701 # 2750
start = 80

frames_data = []
for robot_id, positions in coord_data_smooth.items():
    positions = positions[start:end:frequency]
    for i, pos in enumerate(positions):
        frames_data.append({'Robot': robot_id, 'X': pos[0] - x_0, 'Y': pos[1] - y_0, 'Frame': f'{start + i * frequency}_0', 'size' : 1}) # Со смещением к началу координат
In [22]:
fig = px.scatter(
    frames_data,
    x='X',
    y='Y',
    animation_frame='Frame',
    color='Robot',
    color_continuous_scale=px.colors.sequential.Greens, 
    size = "size",
    opacity = 1,
    width = 600,
    height = 650
)

color_plot = 'lightgrey'

fig.update_layout(
    showlegend=True,
    plot_bgcolor=color_plot,
    coloraxis_showscale=True,
    xaxis_title=None,
    yaxis_title=None,
    xaxis=dict(
        zeroline=False,
        showticklabels=False,
        gridcolor=color_plot
    ),
    yaxis=dict(
        zeroline=False,
        showticklabels=False,
        gridcolor=color_plot
    ),  
    
    margin=dict(l=0, r=0, t=0, b=0)
)

fig.show()
In [23]:
polar_frames_data = []

for robot in frames_data:
    robot_id, x, y, frame, size = robot.values()
    r = math.sqrt(x**2 + y**2)
    phi = math.degrees(math.atan2(y, x))
    polar_frames_data.append({'Robot': robot_id, 'r': r, 'phi': phi, 'Frame': frame, 'size' : size})

fig = px.scatter_polar([frame_i for frame_i in polar_frames_data if frame_i['Frame'] == frame], r="r", theta="phi")
fig.show()
In [24]:
polar_frames_data_square = []   

for robot in polar_frames_data:
    robot_id, r, phi, frame, size = robot.values()
    if math.cos(math.radians(phi)) == 0:
        r_new = r/math.fabs(math.sin(math.radians(phi)))
    elif math.sin(math.radians(phi)) == 0:
        r_new = r/math.fabs(math.cos(math.radians(phi)))
    else:
        r_new = min(r/math.fabs(math.cos(math.radians(phi))), r/math.fabs(math.sin(math.radians(phi))))
    polar_frames_data_square.append({'Robot': robot_id, 'r': r_new, 'phi': phi, 'Frame': frame, 'size' : size})
    
fig = px.scatter_polar([frame_i for frame_i in polar_frames_data_square if frame_i['Frame'] == frame], r="r", theta="phi")
fig.show()
In [25]:
cartesian_frames_data = []

for robot in polar_frames_data_square:
    robot_id, r, phi, frame, size = robot.values()
    
    x = r * math.cos(math.radians(phi))
    y = r * math.sin(math.radians(phi))
    cartesian_frames_data.append({'Robot': robot_id, 'X': int(x), 'Y': int(y), 'Frame': frame, 'size' : size})

fig_frames = px.scatter(
    cartesian_frames_data,
    x='X',
    y='Y',
    color='Robot',
    animation_frame='Frame',
    color_continuous_scale=px.colors.sequential.Greens,
    labels={'X': 'X-координата', 'Y': 'Y-координата'},
    size="size",
    opacity=1,
    width = 600,
    height = 650
)

color_plot = 'lightgrey'

fig_frames.update_layout(
    showlegend=True,
    plot_bgcolor=color_plot,
    coloraxis_showscale=True,
    xaxis_title=None,
    yaxis_title=None,
    xaxis=dict(
        zeroline=False,
        showticklabels=False,
        gridcolor=color_plot
    ),
    yaxis=dict(
        zeroline=False,
        showticklabels=False,
        gridcolor=color_plot
    ),  
    
    margin=dict(l=0, r=0, t=0, b=0)
)

fig_frames.show()
In [26]:
output_path_small = f"experiment_3/image_robot_id/robot_1_circle_small.png"

im = image.imread(output_path_small)
image_size = im.shape[1], im.shape[0]
In [27]:
frame_i_data = [frame for frame in cartesian_frames_data if frame['Frame'] == f'{start}_0']
list_id_robot, list_x, list_y = [], [], []
for params in frame_i_data:
    id_robot = params['Robot']
    x, y = params['X'], params['Y']
    list_id_robot.append(id_robot)
    list_x.append(x)
    list_y.append(y)
In [28]:
dpi=100
fig = plt.figure(figsize=(5, 5), dpi=dpi)
ax = fig.add_subplot(111)

line, = ax.plot(list_x, list_y, "bo", mfc="None",mec="None", markersize=image_size[0] * (dpi/ 100))

ax.set_xlim(-300, 300)
ax.set_ylim(-300, 300)

ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)

plt.subplots_adjust(left=0, right=1, top=1, bottom=0)

line._transform_path()
path, affine = line._transformed_path.get_transformed_points_and_affine()
path = affine.transform_path(path)
for pixelPoint in path.vertices:
    # place image at point, centering it
    fig.figimage(im, pixelPoint[0]- image_size[0]/2, pixelPoint[1]-image_size[1]/2, origin="upper")
    

plt.show() 
No description has been provided for this image

The image was used as input to the image correlation algorithm, the resulting displacement fields:

In [29]:
with open(f'experiment_3/data_set_displacement_smooth_80-700_30_(n=1, speckle, smooth, square, 7x7, noise=False).npy', 'rb') as f:
    data_set_displacement = np.load(f)
In [30]:
size = data_set_displacement[0].shape
max_element = np.amax(data_set_displacement)
min_element = np.amin(data_set_displacement)

print(data_set_displacement.shape)
print(f'max_element = {max_element}, min_element = {min_element}')
(620, 30, 30)
max_element = 1.6074961783062918, min_element = -1.877041213616529
In [31]:
fig = px.imshow(data_set_displacement[::], range_color = [min_element, max_element], color_continuous_scale='viridis', animation_frame=0) # 
fig.show()

In order to use the evolutionary optimization algorithm, it is necessary to smooth the fields:

In [32]:
window_size = 10

def apply_rolling_mean(tensor, window):
    result = np.empty_like(tensor)
    for i in range(tensor.shape[1]):
        for j in range(tensor.shape[2]):
            series = pd.Series(tensor[:, i, j])
            result[:, i, j] = series.rolling(window=window, min_periods=1).mean().values
    return result

smoothed_data_set = apply_rolling_mean(data_set_displacement, window_size)

max_order = 10

def apply_polynomial_smoothing(tensor, max_order):
    smoothed_tensor = np.empty_like(tensor)
    for i in range(tensor.shape[1]):
        for j in range(tensor.shape[2]):
            y = tensor[:, i, j]
            x = np.arange(len(y))
            min_error = float('inf')
            best_fit = y
            
            for order in range(1, max_order + 1):
                coefficients = np.polyfit(x, y, order)
                polynomial = np.polyval(coefficients, x)
                error = np.mean((y - polynomial) ** 2)
                
                if error < min_error:
                    min_error = error
                    best_fit = polynomial
            
            smoothed_tensor[:, i, j] = best_fit
    return smoothed_tensor

smoothed_data_set_2 = apply_polynomial_smoothing(smoothed_data_set, max_order)
In [33]:
fig = px.imshow(smoothed_data_set_2[::], range_color=[np.min(smoothed_data_set_2), np.max(smoothed_data_set_2)], color_continuous_scale='viridis', animation_frame=0) # 
fig.update_layout(
    font_family="Inter Medium",
    font_size=14,
    xaxis_title='x',
    yaxis_title='y',
)

fig.show()

The resulting first and second order equations:

equation_f (first order) = [{
        'du/dx0{power: 1.0}': -0.004022082915156108, 
        'u{power: 1.0}': -5.0189391603073065e-05,
        'du/dx2{power: 1.0}': 0.0008252373606469103, 
        'du/dx2{power: 1.0} * u{power: 1.0}': -0.0017291387624299621,
        'C': 2.104990410020393e-06, 
        'du/dx0{power: 1.0} * du/dx2{power: 1.0}': -1}] 
          
equations_s (second order) = [{
        'du/dx0{power: 1.0}': -0.0049384977227718225, 
        'du/dx2{power: 1.0}': 7.763315096245896e-05,
        'u{power: 1.0}': -0.00015040009758588877, 
        'C': 2.349544122081e-05, 
        'd^2u/dx0^2{power: 1.0}': -1}]

The solution on the interval $ t \in [0, 150]$, since due to the large dimensionality, the computational graph must be memorized to compute the derivatives, which requires a large amount of memory. The solution is obtained using the TEDEouS framework:

In [34]:
solutions_s = torch.load(f'experiment_3/file_u_main_[150, 30, 30]_autograd_slice(0, 150, None)_second_order_eq.pt')
In [35]:
fig = px.imshow(solutions_s, range_color = [np.min(smoothed_data_set_2), np.max(smoothed_data_set_2)], color_continuous_scale='viridis', animation_frame=0)

fig.update_layout(
    font_family="Inter Medium",
    font_size=14,
    xaxis_title='x',
    yaxis_title='y',
)

fig.show()
In [36]:
diff_squared = np.square(solutions_s[30] - smoothed_data_set[30])
rmse = np.sqrt(np.mean(diff_squared))
print("rmse:", rmse)

diff = np.abs(solutions_s[30] - smoothed_data_set[30])
mae = np.mean(diff)
print("mae:", mae)
rmse: 0.18033865018396222
mae: 0.14105575761277653
In [37]:
solutions_f = torch.load(f'experiment_3/file_u_main_[150, 30, 30]_autograd_slice(0, 150, None)_first_order_eq.pt')
In [38]:
fig = px.imshow(solutions_f, range_color = [np.min(smoothed_data_set_2), np.max(smoothed_data_set_2)], color_continuous_scale='viridis', animation_frame=0)

fig.update_layout(
    font_family="Inter Medium",
    font_size=14,
    xaxis_title='x',
    yaxis_title='y',
)

fig.show()
In [39]:
diff_squared = np.square(solutions_f[30] - smoothed_data_set[30])
rmse = np.sqrt(np.mean(diff_squared))
print("rmse:", rmse)

diff = np.abs(solutions_f[30] - smoothed_data_set[30])
mae = np.mean(diff)
print("mae:", mae)
rmse: 0.2125185520909541
mae: 0.16518937299911293

Appendix¶

Repository muDIC: https://github.com/PolymerGuy/muDIC/blob/master/documentation/index.rst

Repository EDPE: https://github.com/ITMO-NSS-team/EPDE

Repository TEDEouS: https://github.com/ITMO-NSS-team/torch_DE_solver